/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
var mxEffects =
{

  /**
	 * Class: mxEffects
	 *
	 * Provides animation effects.
	 */

  /**
	 * Function: animateChanges
	 *
	 * Asynchronous animated move operation. See also: <mxMorphing>.
	 *
	 * Example:
	 *
	 * (code)
	 * graph.model.addListener(mxEvent.CHANGE, function(sender, evt)
	 * {
	 *   var changes = evt.getProperty('edit').changes;
	 *
	 *   if (changes.length < 10)
	 *   {
	 *     mxEffects.animateChanges(graph, changes);
	 *   }
	 * });
	 * (end)
	 *
	 * Parameters:
	 *
	 * graph - <mxGraph> that received the changes.
	 * changes - Array of changes to be animated.
	 * done - Optional function argument that is invoked after the
	 * last step of the animation.
	 */
  animateChanges: function (graph, changes, done) {
    var maxStep = 10
    var step = 0

    var animate = function () {
      var isRequired = false

      for (var i = 0; i < changes.length; i++) {
        var change = changes[i]

        if (change instanceof mxGeometryChange ||
					change instanceof mxTerminalChange ||
					change instanceof mxValueChange ||
					change instanceof mxChildChange ||
					change instanceof mxStyleChange) {
          var state = graph.getView().getState(change.cell || change.child, false)

          if (state != null) {
            isRequired = true

            if (change.constructor != mxGeometryChange || graph.model.isEdge(change.cell)) {
              mxUtils.setOpacity(state.shape.node, 100 * step / maxStep)
            } else {
              var scale = graph.getView().scale

              var dx = (change.geometry.x - change.previous.x) * scale
              var dy = (change.geometry.y - change.previous.y) * scale

              var sx = (change.geometry.width - change.previous.width) * scale
              var sy = (change.geometry.height - change.previous.height) * scale

              if (step == 0) {
                state.x -= dx
                state.y -= dy
                state.width -= sx
                state.height -= sy
              } else {
                state.x += dx / maxStep
                state.y += dy / maxStep
                state.width += sx / maxStep
                state.height += sy / maxStep
              }

              graph.cellRenderer.redraw(state)

              // Fades all connected edges and children
              mxEffects.cascadeOpacity(graph, change.cell, 100 * step / maxStep)
            }
          }
        }
      }

      if (step < maxStep && isRequired) {
        step++
        window.setTimeout(animate, delay)
      } else if (done != null) {
        done()
      }
    }

    var delay = 30
    animate()
  },

  /**
	 * Function: cascadeOpacity
	 *
	 * Sets the opacity on the given cell and its descendants.
	 *
	 * Parameters:
	 *
	 * graph - <mxGraph> that contains the cells.
	 * cell - <mxCell> to set the opacity for.
	 * opacity - New value for the opacity in %.
	 */
  cascadeOpacity: function (graph, cell, opacity) {
    // Fades all children
    var childCount = graph.model.getChildCount(cell)

    for (var i = 0; i < childCount; i++) {
      var child = graph.model.getChildAt(cell, i)
      var childState = graph.getView().getState(child)

      if (childState != null) {
        mxUtils.setOpacity(childState.shape.node, opacity)
        mxEffects.cascadeOpacity(graph, child, opacity)
      }
    }

    // Fades all connected edges
    var edges = graph.model.getEdges(cell)

    if (edges != null) {
      for (var i = 0; i < edges.length; i++) {
        var edgeState = graph.getView().getState(edges[i])

        if (edgeState != null) {
          mxUtils.setOpacity(edgeState.shape.node, opacity)
        }
      }
    }
  },

  /**
	 * Function: fadeOut
	 *
	 * Asynchronous fade-out operation.
	 */
  fadeOut: function (node, from, remove, step, delay, isEnabled) {
    step = step || 40
    delay = delay || 30

    var opacity = from || 100

    mxUtils.setOpacity(node, opacity)

    if (isEnabled || isEnabled == null) {
      var f = function () {
			    opacity = Math.max(opacity - step, 0)
        mxUtils.setOpacity(node, opacity)

        if (opacity > 0) {
          window.setTimeout(f, delay)
        } else {
          node.style.visibility = 'hidden'

          if (remove && node.parentNode) {
            node.parentNode.removeChild(node)
          }
        }
      }
      window.setTimeout(f, delay)
    } else {
      node.style.visibility = 'hidden'

      if (remove && node.parentNode) {
        node.parentNode.removeChild(node)
      }
    }
  }

}
